
#include <assert.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include "Script.h"
#include "UI.h"

using std::cout; using std::endl;

CScript * g_script;

/* construct object with given file name
   and calculate records number */
CScript::CScript(const char * szFileName, const char cHeadFlag)
{
	//open given file
    pParsedFile = new CTextParser(szFileName, cHeadFlag);

	//get the number of records
	nScriptNumber = pParsedFile->GetRecordNum();

	// create index table;
	pTable = new stScriptIndex[nScriptNumber];
	assert(pTable);

    ClearVariables();

	LoadScripts();
}

CScript::~CScript()
{
	if (pScripts){
		delete [] pScripts;
		pScripts = NULL;
	}

	if (pTable) {
		delete [] pTable;
		pTable = NULL;
	}

    if (pParsedFile) {
        delete pParsedFile;
        pParsedFile = NULL;
    }	
}

void CScript::LoadScripts()
{
	char szTemp[256];
	char szName[32];
	short nScriptsIndex = 0;
	nScriptLineNumber = 0;
	
	//calculate line number
	while(pParsedFile->GetWholeLine(szTemp))
	{
		// add entry to index table 
		if( szTemp[0] == pParsedFile->RecordHead() ){
			nIndexInLine = 1;
			CTextParser::ReadSubString(szTemp, &nIndexInLine, szName );
			strcpy(pTable[nScriptsIndex].szScriptName, szName);
			pTable[nScriptsIndex].nIndex = nScriptLineNumber;
			++nScriptsIndex;
		}
		
		++ nScriptLineNumber;		
	}
	
	//malloc memory space to hold scripts
	pScripts = new stScriptLine [ nScriptLineNumber ];
	assert(pScripts);
	
	// read scripts into memory
	pParsedFile->GotoFileHead();
	for ( short i = 0; i < nScriptLineNumber; ++ i )
	{
		pParsedFile->GetWholeLine(szTemp);
		strcpy( pScripts[ i ].szScriptLine, szTemp );	
	}

    delete pParsedFile;
    pParsedFile = NULL;
}

/* Execute a script line. */
void CScript::ExecuteScriptLine()
{
	nIndexInLine = 0;

	// Read command
	char szCommand[32];
    CTextParser::ReadSubString
        (pScripts[nCurrentLine].szScriptLine, &nIndexInLine,
         szCommand);

	char szStringBuffer[256];
	char szNumberBuffer[4];

	//格式：	RETURN
	if ( ! strcmp( szCommand, "RETURN") )
	{
		// Flag = MAIN_MOVE_;
		return;
	}

    else if ( ! strcmp( szCommand, "PRINT") )
    {
        CTextParser::ReadSubString(pScripts[nCurrentLine++].szScriptLine,
                &nIndexInLine, szStringBuffer);
        UI::GetUI()->SystemHint(szStringBuffer);
        return;
    }
	//格式：	IF variable value
	//			...
	//			ENDIF
	// else if ( ! strcmp( szCommand, "IF")
	// 		|| !strcmp(szCommand, "ELSEIF"))
	// {
		
	// 	if ( !Expression() ){	//条件不成立则跳转
	// 		short nested = 0;	//防止if的嵌套
	// 		while(1)
	// 		{
	// 			++ nCurrentLine;
	// 			nIndexInCurLine = 0;
	// 			ReadSubString( pScripts[nCurrentLine].szScriptLine, szCommand);
	// 			if (!strcmp(szCommand, "IF"))
	// 				nested +=1;
	// 			else if (!strcmp(szCommand, "ENDIF") )
	// 			{
	// 				if(nested > 0)
	// 					nested -= 1;
	// 				else break;
	// 			}
	// 			else if( !strcmp(szCommand, "ELSEIF"))
	// 			{
	// 				if (!nested)	break;
	// 			}
	// 		}
	// 		--nCurrentLine;
	// 	}		
	// }

	//格式：	GOTO scriptname
	else if(! strcmp(szCommand, "GOTO"))
	{
		CTextParser::ReadSubString( pScripts[nCurrentLine].szScriptLine,
                &nIndexInLine, szStringBuffer);
		FindScripts( szStringBuffer );
		--nCurrentLine;
	}

	//格式：	CLS
	else if(! strcmp(szCommand, "CLS"))
	{
		// ClrScr();
		// FlipPage();
	}

	//格式：	PLAYSOUND filename
	else if(! strcmp(szCommand, "PLAYSOUND"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// play_sound(szStringBuffer);
	}

	//格式：	DRAWPIC filename width height
	else if(! strcmp(szCommand, "DRAWPIC"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// short width = atoi(szNumberBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// short height = atoi(szNumberBuffer);
		// DrawPic(szStringBuffer, width, height);
		// FlipPage();
	}

	//格式：	SET variable value
	else if(! strcmp(szCommand, "SET"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// SetVariableValue(szStringBuffer, atoi(szNumberBuffer) );
	}

	//格式：	ADDVAR variable [value]
	else if(! strcmp(szCommand, "ADDVAR"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// if( strcmp(szNumberBuffer, ""))	//如果value不为空
		// 	AddVariable( szStringBuffer, atoi(szNumberBuffer));
		// else
		// 	AddVariable(szStringBuffer);
	}

	//格式：	GOTOMAP mapName
	else if(! strcmp(szCommand, "GOTOMAP"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// GotoMap( GetMapAddr(szStringBuffer));
	}

	//格式：	TALK string
	else if(! strcmp(szCommand, "TALK"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// common_diag.set_text(szStringBuffer);
		// common_diag.show(dcBack);
		// FlipPage();
		// oldFlag = Flag;
		// Flag = GAME_MESSAGE_;		
	}

	//格式：	FIGHT name
	else if(!strcmp( szCommand, "FIGHT"))
	{
		// char temp[256];
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// current_enemy = GetFighterAddr(szStringBuffer);
		// sprintf(temp, "你与%s开始战斗！", current_enemy->Name );
		// common_diag.set_text(temp);
		// common_diag.show(dcBack);
		// FlipPage();
		// oldFlag = Flag;	//保存执行脚本的状态
		// Flag = FIGHT_START_;		
	}

	//格式：	REMOVENPC name
	else if(!strcmp( szCommand, "REMOVENPC"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// current_map->DeleteNpc( GetRoleAddr(szStringBuffer));
	}

	//格式：	ADDNPC name x, y
	else if( !strcmp(szCommand, "ADDNPC"))
	{
		// short x, y;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// x = atoi(szNumberBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// y = atoi(szNumberBuffer);
		// current_map->AddNpc( GetRoleAddr(szStringBuffer),x,y);
	}

	//格式：	SETDIR name dir
	else if(! strcmp(szCommand, "SETDIR"))
	{
		// Role * r;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// r = GetRoleAddr(szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// r->Dir = atoi(szNumberBuffer);		
		// RefreshCanvas();
		// FlipPage();
	}

	//格式：	SETSTEP name step
	else if(! strcmp(szCommand, "SETSTEP"))
	{
		// Role * r;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// r = GetRoleAddr(szStringBuffer);		
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// r->Step = atoi(szNumberBuffer);
		// RefreshCanvas();
		// FlipPage();
	}

	//格式：	SETLOCATION name x y
	else if(! strcmp(szCommand, "SETLOCATION"))
	{
		// Role * r;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// r = GetRoleAddr(szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// r->X = atoi(szNumberBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// r->Y = atoi(szNumberBuffer);
		// RefreshCanvas();
		// FlipPage();
	}

	//格式：	MOVENPC name grid_x, grid_y
	else if(! strcmp(szCommand, "MOVENPC"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// current_npc = GetRoleAddr(szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// npc_dest_x = atoi(szNumberBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// npc_dest_y = atoi(szNumberBuffer);
		// oldFlag = Flag;
		// Flag = NPC_MOVE_;
	}

	//格式：	ADDHP name value
	else if(! strcmp(szCommand, "ADDHP"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// Fighter *f = GetFighterAddr( szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// short value = atoi(szNumberBuffer);
		// f->HP += value;
	}

	//格式：	ADDATTACK name value
	else if(! strcmp(szCommand, "ADDATTACK"))
	{
		// Fighter *f;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// f = GetFighterAddr( szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// short value = atoi(szNumberBuffer);
		// f->Attack += value;
	}

	//格式：	ADDDEFEND name value
	else if(! strcmp(szCommand, "ADDDEFEND"))
	{
		// Fighter *f;
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// f = GetFighterAddr( szStringBuffer);
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szNumberBuffer);
		// short value = atoi(szNumberBuffer);
		// f->Defend += value;
	}

	//格式：	REFRESH name
	else if(! strcmp(szCommand, "REFRESH"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// Fighter *f = GetFighterAddr( szStringBuffer);
		// f->cHP = f->HP;
	}

	//格式：	SELECT words
	else if(! strcmp(szCommand, "SELECT"))
	{
		// ReadSubString( pScripts[nCurrentLine].szScriptLine, szStringBuffer);
		// common_diag.set_text(szStringBuffer);
		// common_diag.show(dcBack);
		// FlipPage();
		// oldFlag = Flag;
		// Flag = BEFORE_SELECT_;
	}

	++ nCurrentLine;
	//格式:		ENDIF等
	/*else
	{
		++nCurrentLine;
	}*/

}

void RunScripts(const char * szName )
{
	//oldFlag = Flag;
	// Flag = RUN_SCRIPT_;

	if(g_script->FindScripts(szName))
	{
		g_script->ExecuteScriptLine();
	}
}

void RunScripts()
{
	g_script->ExecuteScriptLine();
}


/* get record number */
/*
short CScript::GetRecordNum()
{
	return nRecordNum;
}*/

bool CScript::FindScripts(const char * szName)
{
	if ( !pScripts )
	{
		return false;
	}
	
	for (int i=0; i< nScriptNumber; ++i)
	{
		if ( ! strcmp(pTable[i].szScriptName, szName) ){
			nCurrentLine = pTable[i].nIndex + 1;
			return true;
		}

	}
	
	return false;
}


void CScript::RunScripts(const char * szName )
{
	if(! FindScripts( szName) )
		return;

    ExecuteScriptLine();	
	// while( strcmp( pScripts[ nCurrentLine].szScriptLine, "RETURN") )
	// {
	// 	//execute scripte line
	// 	ExecuteScriptLine( pScripts[ nCurrentLine].szScriptLine );
	// 	nCurrentLine ++;
	// }
}

void CScript::DebugInfo()
{
    cout << "SCRIPT RECORD: " << nScriptNumber << endl;
    cout << "SCRIPT LINES: " << nScriptLineNumber << endl;
    for(int i = 0; i < nScriptNumber; ++i) {
        cout << pTable[i].nIndex << " : " << pTable[i].szScriptName << endl;
    }
}

bool CScript::Expression(short *nIndexInLine)
{
	char szLHS[32];
	CTextParser::ReadSubString( pScripts[nCurrentLine].szScriptLine, nIndexInLine, szLHS);
	short nLHS = GetVariableValue(szLHS);

	char szOP[8];
    CTextParser::ReadSubString( pScripts[nCurrentLine].szScriptLine, nIndexInLine, szOP);

	char szRHS[32];
	CTextParser::ReadSubString( pScripts[nCurrentLine].szScriptLine, nIndexInLine, szRHS);
	short nRHS = atoi(szRHS);

	if (!strcmp( szOP, "="))
		return nLHS == nRHS;
	else if ( !strcmp(szOP, ">"))
		return nLHS > nRHS;
	else if ( !strcmp(szOP, "<"))
		return nLHS < nRHS;
	else
		return false;

}



void CScript::ClearVariables()
{
	for( int i=0; i< VAR_NUMBER; ++i){
		strcpy( vars[i].szName, "");
	}
}

void CScript::ClearVariable(const char *szName)
{
	for( int i = 0; i < VAR_NUMBER; ++i){
        if(!strcmp(vars[i].szName, szName)){
            strcpy(vars[i].szName, "");
        }
	}
}

short CScript::GetVariableValue(const char * szName )
{
	for( int i = 0; i < VAR_NUMBER; ++i)
	{
		if ( ! strcmp(vars[i].szName, szName))
			return vars[i].nValue;
	}
	return -1;
}

bool CScript::SetVariableValue(const char * szName, short nValue)
{
	for( int i = 0; i < VAR_NUMBER; ++i)
	{
		if ( ! strcmp(vars[i].szName, szName)){
			vars[i].nValue = nValue;
			return true;
		}
	}
	return false;
}

bool CScript::IsVariableExist(const char * szName )
{
	for( int i=0; i< VAR_NUMBER; ++i)
	{
		if ( ! strcmp(vars[i].szName, szName))
			return true;
	}
	return false;
}

bool CScript::AddVariable(const char * szName, short nValue /* = 0 */)
{
	for( int i=0; i< VAR_NUMBER; ++i)
	{
		if ( ! strcmp(vars[i].szName, ""))
		{
			strcpy(vars[i].szName, szName);
			vars[i].nValue = nValue;
			return true;
		}			
	}
	return false;
}
